from datetime import datetime

import wx
from socket import *
import threading  # 创建多线程
from concurrent.futures import ThreadPoolExecutor  # 线程池管理


# 服务端类
class Server(wx.Frame):
    # 构造函数
    def __init__(self):
        # 实例属性
        self.is_on = False  # 服务器启动状态
        self.server_socket = socket()  # socket对象
        # 绑定ip和端口
        self.server_socket.bind(('0.0.0.0', 8999))
        # 监听
        self.server_socket.listen(5)
        # 保存所有的客户端
        self.client_thread_dict = {}
        # 创建一个线程池，用于管理线程  最大线程数为5
        self.pool = ThreadPoolExecutor(max_workers=5)

        # 界面布局
        # 初始化一个wx.Frame窗口
        wx.Frame.__init__(self, None, title='多人聊天室服务端', pos=(50, 100), size=(600, 600))
        # 界面布局
        # 创建面板
        self.pl = wx.Panel(self)

        # 创建按钮
        # 启动服务器
        self.start_server_btn = wx.Button(self.pl, label='启动服务器', pos=(10, 10), size=(200, 30))
        # 保存聊天记录
        self.save_text_btn = wx.Button(self.pl, label='保存聊天记录', pos=(300, 10), size=(200, 30))

        # 聊天内容文本框
        self.text = wx.TextCtrl(self.pl, pos=(10, 50), size=(560, 350), style=wx.TE_READONLY | wx.TE_MULTILINE)

        # 按钮的绑定事件
        self.Bind(wx.EVT_BUTTON, self.start_server, self.start_server_btn)
        self.Bind(wx.EVT_BUTTON, self.save_text, self.save_text_btn)

    # 事件方法
    # 启动服务器
    def start_server(self, event):
        print('启动服务器...')
        if not self.is_on:
            self.is_on = True
            # 开启一个线程，用于接收客户端连接
            main_thread = threading.Thread(target=self.main_thread_fun)
            # 设置为守护线程，主线程结束后，子线程也结束
            main_thread.daemon = True
            # 启动线程
            main_thread.start()

    # 接收客户端消息
    def main_thread_fun(self):
        while self.is_on:
            # 接收客户端连接 返回客户端套接字和客户端地址
            client_socket, client_addr = self.server_socket.accept()
            print('客户端连接成功：', client_addr, 'socket:', client_socket.fileno())
            # 接收客户端发送的昵称
            client_name = client_socket.recv(1024).decode('utf8')
            print(client_name, '加入聊天室')

            client_thread = ClientThread(client_socket, client_name, self)
            # 保存客户端信息
            self.client_thread_dict[client_name] = client_thread
            # 提交到线程池中
            self.pool.submit(client_thread.run)
            self.send_text('【服务器通知】欢迎' + client_name + '加入聊天室\n')

    # 群发消息
    def send_text(self, text):
        # 获取当前时间
        time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        text = '【' + time + '】 '   + text + '\n'
        self.text.AppendText(text)
        for client in self.client_thread_dict.values():
            if client.is_on:
                client.client_socket.send(text.encode('utf8'))

    # 保存聊天记录
    def save_text(self, event):
        print('保存聊天记录')
        record = self.text.GetValue()
        with open('聊天记录.txt', 'a+', encoding='utf8') as f:
            f.write(record)


# 客户端线程类
class ClientThread(threading.Thread):
    def __init__(self, socket, name, server):
        threading.Thread.__init__(self)
        self.client_socket = socket
        self.client_name = name
        self.server = server
        self.is_on = True

    def run(self):
        while self.is_on:

            # 接收客户端发送的消息
            recv_data = self.client_socket.recv(1024).decode('utf8')
            if recv_data == '断开连接':
                self.is_on = False
                self.server.send_text('【服务器通知】' + self.client_name + '退出聊天室\n')
            else:
                # 群发消息
                self.server.send_text(self.client_name + ':\n' + recv_data)

        self.client_socket.close()
        # 从字典中删除客户端信息
        del self.server.client_thread_dict[self.client_socket]


# 程序入口
if __name__ == '__main__':
    # 创建应用程序对象
    app = wx.App()
    # 创建客户端窗口
    server = Server()
    # 显示客户端窗口
    server.Show()

    # 循环显示
    app.MainLoop()
